package qsoft.omanga.common.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class AsyncLoad {

	private static final AsyncLoad ASYNC = new AsyncLoad();

	public static final AsyncLoad getInstance() {
		return ASYNC;
	}

	/**
	 * 
	 * @param url
	 *            The URL of the image to download.
	 * @param imageView
	 *            The ImageView to bind the downloaded image to.
	 */
	public void forceLoad(ImageView imageView, String id, String url, String imageSize) {
		Cache.getInstance().resetPurgeTimer();
		Bitmap bitmap = Cache.getInstance().getBitmapFromCache(url);

		if (bitmap == null) {
			loadNet(imageView, id, url, imageSize);
		} else {
			cancelPotentialDownload(url, imageView);
			imageView.setImageBitmap(bitmap);
		}
	}

	/**
	 * Same as download but the image is always downloaded and the cache is not
	 * used. Kept private at the moment as its interest is not clear.
	 */
	private void loadNet(ImageView imageView, String id, String url, String imageSize) {
		if (url == null) {
			imageView.setImageDrawable(null);
			return;
		}

		if (cancelPotentialDownload(url, imageView)) {
			LoaderTask task = new LoaderTask(imageView);
			DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
			imageView.setImageDrawable(downloadedDrawable);
			imageView.setMinimumHeight(156);
			task.execute(url);
		}
	}

	/**
	 * Returns true if the current download has been canceled or if there was no
	 * download in progress on this image view. Returns false if the download in
	 * progress deals with the same url. The download is not stopped in that
	 * case.
	 */
	private static boolean cancelPotentialDownload(String url,
			ImageView imageView) {
		LoaderTask loaderTask = getLoaderTask(imageView);

		if (loaderTask != null) {
			String bmpURL = loaderTask.url;
			if ((bmpURL == null) || (!bmpURL.equals(url))) {
				loaderTask.cancel(true);
			} else {
				// The same URL is already being downloaded.
				return false;
			}
		}
		return true;
	}

	/**
	 * @param imageView
	 *            Any imageView
	 * @return Retrieve the currently active download task (if any) associated
	 *         with this imageView. null if there is no such task.
	 */
	private static LoaderTask getLoaderTask(ImageView imageView) {
		if (imageView != null) {
			Drawable drawable = imageView.getDrawable();
			if (drawable instanceof DownloadedDrawable) {
				DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
				return downloadedDrawable.getLoaderTask();
			}
		}
		return null;
	}

	private Bitmap downloadBitmap(String txtURL) {
		Bitmap bitmap = null;
		try {
			Log.i("LOAD NET" + txtURL, "LOAD NET " + txtURL + " RUNNING..");
			URLConnection conn;
			URL url = new URL(txtURL);
			conn = url.openConnection();
			conn.setUseCaches(true);
			InputStream is = conn.getInputStream();
			bitmap = BitmapFactory.decodeStream(is);
			is.close();
		} catch (MalformedURLException e) {
			Log.e("MalformedURLException", e.getMessage());
		} catch (IOException e) {
			Log.e("IOException", e.getMessage());
		}
		return bitmap;
	}

	/**
	 * The actual AsyncTask that will asynchronously download the image.
	 */
	private class LoaderTask extends AsyncTask<String, Void, Bitmap> {
		private String url;
		private final WeakReference<ImageView> imageViewReference;

		public LoaderTask(ImageView imageView) {
			imageViewReference = new WeakReference<ImageView>(imageView);
		}

		/**
		 * Actual download method.
		 */
		@Override
		protected Bitmap doInBackground(String... params) {
			url = params[0];
			return downloadBitmap(url);
		}

		/**
		 * Once the image is downloaded, associates it to the imageView
		 */
		@Override
		protected void onPostExecute(Bitmap bitmap) {
			Bitmap bmp = bitmap;
			if (isCancelled()) {
				return;
			}
			Cache.getInstance().addBitmapToCache(url, bmp);
			if (imageViewReference != null) {
				ImageView imageView = imageViewReference.get();
				LoaderTask loaderTask = getLoaderTask(imageView);
				if ((this == loaderTask)) {
					imageView.setImageBitmap(bmp);
				}
			}
		}
	}

	/**
	 * A fake Drawable that will be attached to the imageView while the download
	 * is in progress.
	 * 
	 * <p>
	 * Contains a reference to the actual download task, so that a download task
	 * can be stopped if a new binding is required, and makes sure that only the
	 * last started download process can bind its result, independently of the
	 * download finish order.
	 * </p>
	 */
	private static class DownloadedDrawable extends ColorDrawable {
		private final WeakReference<LoaderTask> loaderTaskReference;

		public DownloadedDrawable(LoaderTask bitmapDownloaderTask) {
			super(Color.TRANSPARENT);
			loaderTaskReference = new WeakReference<LoaderTask>(
					bitmapDownloaderTask);
		}

		public LoaderTask getLoaderTask() {
			return loaderTaskReference.get();
		}
	}
}
